/**
 * @file fastus_cd22_485.cpp
 * @details fastus 点激光位移传感器控制代码，实现了基本的功能。
 * @copyright 北京经海科技有限公司
 * @author 李渊 <18069211@qq.com>
 * @version 1.0
 * @date 2017.02.05
 */

#include "fastus_cd22_485.h"
#include <QSerialPortInfo>
#include <QDebug>
const unsigned char STX = 0x02;
const unsigned char ETX = 0x03;
const unsigned char ACK = 0x06;
const unsigned char NAK = 0x15;

const unsigned char CMD_C = 0x43;
const unsigned char CMD_W = 0x57;
const unsigned char CMD_R = 0x52;

FASTUS_CD22_485::FASTUS_CD22_485(QObject *parent)
    :QObject(parent)
{
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        if( info.serialNumber() == "AI0240GEA" )
        {
            m_reader.setPort(info);
            if(m_reader.open(QIODevice::ReadWrite))
            {
                qDebug() << "Name : " << info.portName();
                qDebug() << "Description : " << info.description();
                qDebug() << "serialNumber: " << info.serialNumber();

                m_reader.setBaudRate(QSerialPort::Baud115200);
                m_reader.setParity(QSerialPort::NoParity);
                m_reader.setDataBits(QSerialPort::Data8);
                m_reader.setStopBits(QSerialPort::OneStop);
                m_reader.setFlowControl(QSerialPort::NoFlowControl);

                m_reader.clearError();
                m_reader.clear();
                connect(&m_reader, SIGNAL(readyRead()), this, SLOT(readCom()));
            }
            break;
        }
    }
    m_state = STATE_IDLE;
    m_command = CMD_IDLE;
}


void FASTUS_CD22_485::cmd_C(char c1, char c2)
{
    char cmd[6] = {STX, CMD_C, 0x00, 0x00, ETX, 0 };
    cmd[2] = c1;
    cmd[3] = c2;
    cmd[5] = cmd[1] ^ cmd[2] ^ cmd[3];
    m_reader.write(cmd, 6);
}

void FASTUS_CD22_485::cmd_R(char c1, char c2)
{
    char cmd[6] = {STX, CMD_R, 0x00, 0x00, ETX, 0 };
    cmd[2] = c1;
    cmd[3] = c2;
    cmd[5] = cmd[1] ^ cmd[2] ^ cmd[3];
    m_reader.write(cmd, 6);
}

void FASTUS_CD22_485::cmd_W(char c1, char c2)
{
    char cmd[6] = {STX, CMD_W, 0x00, 0x00, ETX, 0 };
    cmd[2] = c1;
    cmd[3] = c2;
    cmd[5] = cmd[1] ^ cmd[2] ^ cmd[3];
    m_reader.write(cmd, 6);
}

void FASTUS_CD22_485::cmdRead()
{
    m_command = CMD_READ;
    cmd_C(0xb0, 0x01);
}

void FASTUS_CD22_485::cmdJudge()
{
    m_command = CMD_JUDGE;
    cmd_C(0xb0, 0x02);
}

void FASTUS_CD22_485::cmdSaveSettings()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa0, 0x00);
}

void FASTUS_CD22_485::cmdUndoSettings()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa0, 0x01);
}

void FASTUS_CD22_485::cmdLaserOn()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa0, 0x03);
}

void FASTUS_CD22_485::cmdLaserOff()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa0, 0x02);
}

void FASTUS_CD22_485::cmdInit()
{
    m_command = CMD_ACK0000;
    cmd_C(0x40, 0x00);
}

void FASTUS_CD22_485::cmdLock()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa1, 0x04);
}

void FASTUS_CD22_485::cmdUnlock()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa1, 0x05);
}

void FASTUS_CD22_485::cmdZero()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa1, 0x00);
}

void FASTUS_CD22_485::cmdUnzero()
{
    m_command = CMD_ACK0000;
    cmd_C(0xa1, 0x01);
}

void FASTUS_CD22_485::readFarEndThreshold()
{
    m_command = CMD_READ_PARA;
    cmd_R(0x41, 0x00);
}

void FASTUS_CD22_485::readNearEndThreshold()
{
    m_command = CMD_WRITE_STAGE1;
    cmd_R(0x41, 0x02);
}

void FASTUS_CD22_485::writeFarEndThreshold(int16_t data)
{
    m_command = CMD_WRITE_STAGE1;
    m_data = data;
    cmd_R(0x41, 0x00);
}

void FASTUS_CD22_485::writeNearEndThreshold(int16_t data)
{
    m_command = CMD_WRITE_STAGE1;
    m_data = data;
    cmd_R(0x41, 0x02);
}

void FASTUS_CD22_485::writeSamplePeriod(int16_t data)
{
    m_command = CMD_WRITE_STAGE1;
    m_data = data;
    cmd_R(0x40, 0x06);
}

void FASTUS_CD22_485::readSamplePeriod()
{
    m_command = CMD_READ_PARA;
    cmd_R(0x40, 0x06);
}

void FASTUS_CD22_485::readAveragePara()
{
    m_command = CMD_READ_PARA;
    cmd_R(0x40, 0x0A);
}

void FASTUS_CD22_485::writeAveragePara(int16_t data)
{
    m_command = CMD_WRITE_STAGE1;
    m_data = data;
    cmd_R(0x40, 0x0A);
}

void FASTUS_CD22_485::readSensibility()
{
    m_command = CMD_READ_PARA;
    cmd_R(0x40, 0x14);
}

void FASTUS_CD22_485::writeSensibility(int16_t data)
{
    m_command = CMD_WRITE_STAGE1;
    m_data = data;
    cmd_R(0x40, 0x14);
}

void FASTUS_CD22_485::stateMachine(char c)
{
    switch(m_state)
    {
    case STATE_IDLE:
        if(c == STX)
        {
//            qDebug() << "To STATE_STX";
            m_state = STATE_STX;
        }
        break;
    case STATE_STX:
        inStateSTX(c);
        break;
    case STATE_ACK:
    case STATE_NAK:
        m_message[1] = c;
        m_state = STATE_DATA1;
//        qDebug() << "To STATE_DATA1";
        break;

    case STATE_DATA1:
        m_message[2] = c;
        m_state = STATE_DATA2;
//        qDebug() << "To STATE_DATA2";
        break;

    case STATE_DATA2:
        if(c == ETX)
        {
            m_state = STATE_ETX;
//            qDebug() << "To STATE_ETX";
        }
        else
        {
            m_state = STATE_IDLE;
//            qDebug() << "To STATE_IDLE";
        }
        break;
    case STATE_ETX:
        inStateETX(c);
        break;
    }
}

void FASTUS_CD22_485::dispatchData(int16_t data)
{
    switch(m_command)
    {
    case CMD_READ:
        emit dataReceived(data);
        break;
    case CMD_JUDGE:
        emit judgementReceived(data & 0x01);
        break;
    case CMD_ACK0000:
        emit commandAcknowledged();
        break;
    case CMD_READ_PARA:
        emit readParaReceived(data);
        break;
    case CMD_WRITE_STAGE1:
        m_command = CMD_WRITE_STAGE1;
        cmd_W((m_data >> 8) & 0xff, m_data & 0xff);
        break;
    case CMD_WRITE_STAGE2:
        emit writeFinished();
        break;
    }
}

void FASTUS_CD22_485::inStateETX(char c)
{
    m_state = STATE_IDLE;

    if( c == (m_message[0] ^ m_message[1] ^ m_message[2]) )
    {
        if(m_message[0] == ACK)
        {
            int16_t data;
            uint8_t * p = reinterpret_cast<uint8_t *> (&data);
            p[0] = m_message[2];
            p[1] = m_message[1];
            dispatchData(data);
        }
        else if(m_message[0] == NAK)
        {
            emit commError(m_message[1]);
        }
    }
//    qDebug() << "TO STATE_IDLE";
//    m_command  = CMD_IDLE;
}

void FASTUS_CD22_485::inStateSTX(char c)
{
    m_message[0] = c;
    if(c == ACK)
    {
        m_state = STATE_ACK;
        //qDebug() << "To STATE_ACK";
    }
    else if(c == NAK)
    {
        m_state = STATE_NAK;
        //qDebug() << "To STATE_NAK";
    }
    else
    {
        m_state = STATE_IDLE;
        //qDebug() << "To STATE_IDLE";
    }
}

void FASTUS_CD22_485::readCom()
{
    QByteArray data = m_reader.readAll();
    for (int i = 0; i < data.size(); ++i)
    {
        stateMachine(data.at(i));
    }
}
